﻿using CfgTable;
using IQIGame.Onigao.Framework;
using NetProtocol.POD;
using System;
using System.Collections.Generic;

namespace IQIGame.Onigao.GamePlay
{
    public class HeroSkill : SkillBaseData
    {
        public HeroData belongHero { get; private set; }
        public HeroSkill() { }

        public HeroSkill Sync(int skillCid, int skillLev, bool isUnlock, HeroData belongHero)
        {
            base.Sync(skillCid, skillLev, isUnlock);
            this.belongHero = belongHero;
            return this;
        }

        protected override void OnClear()
        {
            this.belongHero = null;
        }

        #region 对象池
        static public new HeroSkill NewFromPool()
        {
            return ClassPool.Get<HeroSkill>();
        }
        #endregion
    }

    public class HeroData : IReusableClass
    {
        /*-- members --*/
        /// <summary>
        /// 英雄唯一id
        /// </summary>
        public long id { get; private set; }
        /// <summary>
        ///  英雄cid
        /// </summary>
        public int cid { get; private set; }
        /// <summary>
        ///  觉醒等级
        /// </summary>
        public int awakenLevel { get; private set; }
        /// <summary>
        ///  等级
        /// </summary>
        public int level { get; private set; }
        /// <summary>
        ///  经验 -- 当前等级
        /// </summary>
        public int exp { get; private set; }
        /// <summary>
        ///  星级
        /// </summary>
        public int star { get; private set; }
        /// <summary>
        ///  皮肤cid -- 默认皮肤也穿上
        /// </summary>
        public int skinCid { get; set; }
        /// <summary>
        ///  战斗力
        /// </summary>
        public int fightPower { get; private set; } = 0;

        /// <summary>
        ///  装备的宠物
        /// </summary>
		public long petId { get; private set; }

        /// <summary>
        ///  装备的缘起阶段
        /// </summary>
        public int fateTrajectoryStage { get; private set; }

        /// <summary>
        ///  技能id到等级--技能强化
        /// </summary>
        private Dictionary<int, HeroSkill> m_skills;
        public Dictionary<int, HeroSkill> skills
        {
            get
            {
                if (m_skills == null)
                {
                    m_skills = new(4);
                }
                return m_skills;
            }
            private set
            {
                m_skills = value;
            }
        }
        /// <summary>
        ///  属性 -- 全发
        /// </summary>
        private int[] _attrs;
        public int[] attrs => this._attrs;
        public int GetAttr(int attrType)
        {
            return this._attrs[attrType];
        }

        public int GetAttr(EAttributeType attrType)
        {
            return this.GetAttr((int)attrType);
        }

        /// <summary>
        ///  穿戴的装备，位置 -> 物品唯一id
        /// </summary>
        private Dictionary<int, long> m_equips;
        public Dictionary<int, long> equips
        {
            get
            {
                if (m_equips == null)
                {
                    m_equips = new();
                }
                return m_equips;
            }
            private set
            {
                m_equips = value;
            }
        }

        /// <summary>
        /// 是否已拥有
        /// </summary>
        public bool isGeted => this.id > 0;

        private CfgHero _cfgData;
        public CfgHero cfgData
        {
            get
            {
                if (this._cfgData == null && this.cid > 0)
                {
                    this._cfgData = TableCenter.hero.Get(this.cid);
                }
                return this._cfgData;
            }
        }
        public CfgHeroSkin cfgSkin => TableCenter.heroSkin.Get(this.skinCid);
        public CfgSoul cfgSoul => TableCenter.soul.Get(this.cfgData.SoulId);
        public CfgHeroLevel cfgLv => TableCenter.heroLevel.Get(this.level);

        public CfgHeroStar cfgStar
        {
            get
            {
                return TableCenter.heroStar.GetCfg(this.cid, this.star);
            }
        }

        public CfgHeroAwaken cfgAwaken
        {
            get
            {
                return this.GetCfgHeroAwaken(this.awakenLevel);
            }
        }

        public int maxAwakenLv
        {
            get
            {
                var cfg = TableCenter.heroAwaken.MaxCfg(this.cid);
                int max = cfg?.AwakenLevel ?? -1;
                int maxLimit = TableCenter.global.MaxHeroAwakenLv;
                return Math.Min(max, maxLimit);
            }
        }

        private int maxLimitHeorLv
        {
            get
            {
                var lmtLv = this.maxAwakenLv;
                var cfgAwaken = this.GetCfgHeroAwaken(lmtLv);
                int result = cfgAwaken?.MaxHeroLevel ?? 30;
                return result;
            }
        }

        public int maxLv
        {
            get
            {
                var cfgAwaken = this.cfgAwaken;
                int result = cfgAwaken?.MaxHeroLevel ?? this.maxLimitHeorLv;
                return result;
            }
        }

        public bool isMaxLvCanAwaken => (this.maxLv <= this.level) && (this.level < this.maxLimitHeorLv);

        public HeroData()
        {
        }

        public CfgHeroAwaken GetCfgHeroAwaken(int awakenLv)
        {
            return TableCenter.heroAwaken.GetCfg(this.cid, awakenLv);
        }

        public HeroData Sync(HeroPOD pod)
        {
            this.id = pod.id;
            this._attrs = pod.attrs;
            this.awakenLevel = pod.awakenLevel;
            this.cid = pod.cid;
            this.equips = pod.equips;
            this.exp = pod.exp;
            this.level = pod.level;
            this.skinCid = pod.skinCid;
            this.star = pod.star;
            this.petId = pod.petId;
            this.fateTrajectoryStage = pod.fateTrajectory;

            int cnt = pod.skills.Count;

            foreach (var item in pod.skills)
            {
                if (!this.skills.TryGetValue(item.Key, out var skill))
                {
                    skill = HeroSkill.NewFromPool();
                    this.skills[item.Key] = skill;
                }
                skill.Sync(item.Key, item.Value, true, this);
            }

            var defSkill = cfgData.DefaultSkill;
            int cntSkill = defSkill.Count;
            if (cnt < cntSkill)
            {
                foreach (var item in defSkill)
                {
                    if (!this.skills.TryGetValue(item, out var skill))
                    {
                        skill = HeroSkill.NewFromPool().Sync(item, 1, false, this);
                        this.skills[item] = skill;
                    }
                }
            }
            return this;
        }

        #region 装备逻辑
        public ItemEquipmentData GetWearEquipItem(int equipColumn)
        {
            if (equipColumn > 0 && this.equips.TryGetValue(equipColumn, out var equipId))
            {
                if (GameDataCenter.PlayerData.item.TryGetItem(equipId, out var equipItemWear))
                {
                    return equipItemWear as ItemEquipmentData;
                }
            }
            return null;
        }

        public int GetWearEquipColumn(ItemEquipmentData equipItem)
        {
            foreach (var item in this.equips)
            {
                if (item.Value == equipItem.id)
                {
                    return item.Key;
                }
            }
            return -1;
        }

        public int GetWearSameCidEquipColumn(ItemEquipmentData equipItem)
        {
            foreach (var item in this.equips)
            {
                if (item.Value > 0 && GameDataCenter.PlayerData.item.TryGetItem(item.Value, out var equipItemWear))
                {
                    if (equipItemWear.cid == equipItem.cid)
                        return item.Key;
                }
            }
            return -1;
        }

        public bool IsWearEquip()
        {
            foreach (var item in this.equips)
            {
                if (item.Value > 0 && GameDataCenter.PlayerData.item.IsContainsItem(item.Value))
                {
                    return true;
                }
            }
            return false;
        }

        public bool IsWearPet()
        {
            return this.petId > 0 && GameDataCenter.PlayerData.pet.ContainsKey(this.petId);
        }
        #endregion

        public void Clear()
        {
            this.id = 0;
            this.cid = 0;
            this._cfgData = null;
            this.awakenLevel = 0;
            this.level = 0;
            this.exp = 0;
            this.star = 0;
            this.skinCid = 0;
            this.fightPower = 0;
            this.petId = 0;
            this.fateTrajectoryStage = 0;
            if (this.m_skills != null)
            {
                foreach (var item in this.m_skills.Values)
                {
                    item.Put2Pool();
                }
            }
            this.m_skills = null;
            this._attrs = null;
            this.m_equips = null;
        }

        #region 对象池
        public uint MaxStore => 30;

        public void OnReset()
        {
            this.Clear();
        }

        public void Put2Pool()
        {
            ClassPool.Put(this);
        }

        static public HeroData NewFromPool()
        {
            return ClassPool.Get<HeroData>();
        }
        #endregion

        static public HeroData ConvertFromPOD(HeroPOD pod)
        {
            if (pod == null)
            {
                return null;
            }
            HeroData ret = NewFromPool().Sync(pod);
            return ret;
        }

        static public HeroData ConvertFromCfg(CfgHero cfg)
        {
            HeroData ret = NewFromPool();
            var listAttrs = TableCenter.attribute.DataList;
            ret._attrs = new int[listAttrs.Count + 1];
            for (var i = 0; i < cfg.AttType.Count; i++)
            {
                ret.attrs[cfg.AttType[i]] = cfg.AttValue[i];
            }
            ret.cid = cfg.Id;
            ret.exp = 0;
            ret.level = 1;
            var skill = ret.skills;
            foreach (var item in cfg.DefaultSkill)
            {
                var _cfgSkill = TableCenter.skill.Get(item);
                skill[item] = HeroSkill.NewFromPool().Sync(item, 1, _cfgSkill.UnlockHeroLevel <= 1, ret);
            }
            ret.star = cfg.DefaultStar;
            ret.skinCid = cfg.HeroSkinIds[0];
            return ret;
        }
    }

    public class HeroModuleData
    {
        protected Dictionary<int, HeroData> dicCidHero { get; private set; }
        protected Dictionary<long, int> dicIdCid { get; private set; }

        public HeroModuleData()
        {
            this.dicCidHero = new();
            this.dicIdCid = new();
        }

        public void Clear()
        {
            foreach (var item in this.dicCidHero.Values)
            {
                item.Put2Pool();
            }
            this.dicCidHero.Clear();
            this.dicIdCid.Clear();
        }

        public bool FindHeroDataByCid(int cid, out HeroData heroData)
        {
            return this.dicCidHero.TryGetValue(cid, out heroData);
        }

        public void Put(HeroData heroData)
        {
            this.dicCidHero[heroData.cid] = heroData;
        }

        public bool ContainsKey(int cid)
        {
            return this.dicCidHero.ContainsKey(cid);
        }

        public bool Remove(int cid)
        {
            return this.dicCidHero.Remove(cid);
        }

        public bool Remove(int cid, out HeroData heroData)
        {
            return this.dicCidHero.Remove(cid, out heroData);
        }

        public List<HeroData> GetHeros(System.Func<HeroData, bool> funcFitlerAdd)
        {
            var dic = this.dicCidHero;
            int capacity = Math.Max(dic.Count / 4, 4);
            List<HeroData> result = new(capacity);
            foreach (var item in dic.Values)
            {
                if (funcFitlerAdd == null || funcFitlerAdd(item))
                {
                    result.Add(item);
                }
            }
            return result;
        }

        public List<HeroData> GetSortHeros(System.Func<HeroData, bool> funcFitlerAdd, Comparison<HeroData> sortFunc)
        {
            var result = this.GetHeros(funcFitlerAdd);
            if (result.Count > 1 && sortFunc != null)
            {
                result.Sort(sortFunc);
            }
            return result;
        }

        public void PutIdCid(HeroData heroData)
        {
            if (heroData.id == 0)
            {
                throw new ArgumentOutOfRangeException("Server's HeroData id is zero");
            }
            this.dicIdCid[heroData.id] = heroData.cid;
        }

        /// <summary>
        /// 通过英雄唯一id查询英雄
        /// </summary>
        /// <param name="id">唯一id</param>
        /// <returns></returns>
        public HeroData FindHeroDataById(long id)
        {
            if (this.dicIdCid.TryGetValue(id, out var cid))
            {
                if (this.FindHeroDataByCid(cid, out var heroData))
                {
                    return heroData;
                }
            }
            return null;
        }

        public HeroData GetEquipWearer(long equipId)
        {
            if (equipId == 0)
                return null;
            foreach (HeroData heroData in dicCidHero.Values)
            {
                foreach (var item in heroData.equips)
                {
                    if (item.Value == equipId)
                        return heroData;
                }
            }
            return null;
        }

        public HeroData GetPetWearer(long petId)
        {
            if (petId == 0)
                return null;
            foreach (HeroData heroData in dicCidHero.Values)
            {
                if (heroData.petId == petId)
                    return heroData;
            }
            return null;
        }
    }
}
